
#==========================================================#
# Visualizing Facebook networks with friend photos         #
# Katya Ognyanova, www.kateto.net, @ognyanova              #
#==========================================================#
 
# Find more details at http://bit.ly/fbgephi

#==========================================================#
#### Collect the data using the RFacebook package       ####

install.packages("Rfacebook")   
library(Rfacebook)

# To get authenticated, first register as a developer here: 
# https://developers.facebook.com/apps and create a new app.
# Then replace "123456789" below with the actual info
# you'll find in the "Settings" panel of your app.
# You also need to set Settings -> Website -> Site URL
# there to be http://localhost:1410/

oauth <- fbOAuth(app_id = "123456789", 
                 app_secret = "123456789",
                 extended_permissions = T)

save(oauth, file="fb_oauth")
# load(file="fb_oauth")
 
# Get friend info:
my.friends <- getFriends(oauth, simplify=F)
head(my.friends)
colnames(my.friends)
  
# Get friend network in two formats, matrix and edgelist: 
fb.net.mat <-  getNetwork(oauth, format = "adj.matrix")+0 # boolean, +0 to get numeric
fb.net.el  <- as.data.frame(getNetwork(oauth, format = "edgelist"))


#==========================================================#
#### Download friend profile photos from Fb             ####

setwd("C:/Research/R") 
dir.create("FbImages")

# Image file name and local path stored here:
my.friends$picture.dld <- NA


# Download the images:

for (i in 1:dim(my.friends)[1]) { 
  # Fb images appear to be mostly JPEGs, except for people 
  # with no profile pics - for those we seem to get a default GIF
  pic.ext <- ".jpg" 
  if(grepl(".gif$", my.friends$picture[i])) pic.ext <- ".gif"
  
  # We'll name files using people's full names plus file extension.   
  my.friends$picture.dld[i] <- paste0("FBImages/", sub(" ", "_", my.friends$name[i]), pic.ext)
  
  # Some users have UTF-8 encoded names that don't work well as file names:
  if (Encoding(my.friends$name[i])=="UTF-8") {
    my.friends$picture.dld[i] <- paste0("FBImages/", "FbID_", my.friends$id[i], pic.ext) }
  
 download.file(my.friends$picture[i],  my.friends$picture.dld[i],  mode = 'wb')  
}


#==========================================================#
#### Save the data for import into Gephi                ####

# Two files: an edgelist csv containing Source and Target columns,
# and a node attributes csv, containing IDs that match those in the 
# Source/Target columns.  To use the Gephi Image preview plugin, 
# we also need a column called "image" and containing 
# the file name of each picture. 

colnames(fb.net.el) <- c("Source", "Target")
my.friends$ID <- my.friends$name
my.friends$image <- gsub("FBImages/(*.)", "\\1", my.friends$picture.dld)
 
write.csv(fb.net.el, file="Facebook-friend-EDGES.csv", row.names=F)
write.csv(my.friends, file="Facebook-friend-NODES.csv" row.names=F)

# Note that we could use other formats like gexf for the export/import, 
# but in my experience for simple nets that just ends up being more work 
# than going with the csv files.


#==========================================================#
#### Plot the network using the igraph package          ####

require("png")
require("jpeg")
require("igraph")

fb.net <- graph.adjacency(fb.net.mat)

# Add node degree, node colors based on gender, and
# edge colors based on the color of the source node.
my.friends$degree <- degree(fb.net)
my.friends$color <- "gray45"
my.friends$color[my.friends$gender=="female"] <- "lightpink3"
my.friends$color[my.friends$gender=="male"]   <- "lightblue"
fb.net.el$color <- my.friends$color[match(fb.net.el$Source, my.friends$name)]

l <- layout.fruchterman.reingold(fb.net, niter=10000,area=vcount(fb.net)^2.3,
                                  repulserad=vcount(fb.net)^2.65)

png("Facebook-friends-net-IGRAPH.png", width = 2500, height = 2000)
plot(fb.net, vertex.size=my.friends$degree/20, vertex.label=NA, 
     vertex.color=my.friends$color, edge.color=fb.net.el$color,
     edge.width=1, edge.arrow.size=0, edge.curved=0.3,  layout=l)
dev.off()


# Now plot using images for the nodes:

# Rescale the layout so it goes from -1 to 1
l <- layout.norm(l, -1, 1, -1, 1)
 
png("Facebook-friends-net-IGRAPH-Photos.png", width = 2500, height = 2000)

plot(fb.net, vertex.size=4, vertex.label=NA, edge.color=fb.net.el$color, 
     vertex.shape="square",vertex.color="white", vertex.frame.color="white",
     edge.width=1, edge.arrow.size=0, edge.curved=0.2,  layout=l)

img.sc <- 0.03 #Image scaling
for (i in 1:dim(l)[1]) {
  img <- my.friends$picture.dld[i]
  img <- if(grepl(".jpg", img)) readJPEG(img) else "gray20"
  rasterImage(img, l[i,1]-img.sc, l[i,2]-img.sc, l[i,1]+img.sc, l[i,2]+img.sc)
}

dev.off()

detach(package:png)
detach(package:jpeg)
detach(package:igraph)


#==========================================================#
#### Plot the network using the qgraph package          ####

require("png")
require("qgraph")
 
png("Facebook-friends-net-QGRAPH.png", width = 2500, height = 2000)

qgraph(fb.net.mat, images = my.friends$picture.dld, labels = F, 
       borders = F, esize=0.1, curve=0.2, curveAll=T, edge.color="gray55")

dev.off()

detach(package:png)
detach(package:qgraph)
 
#==========================================================##
